<template>
  <div class="_slide" ref="slideRef">
    <div class="backdrop"></div>
    <div class="inner">
      <slot></slot>
      <div class="_dot-wrapper" v-if="hasDot">
        <div class="_dot-item" v-for="item in itemLength" :key="item">
          <a
            href="javascript:;"
            class="dot-link"
            :style="{
              backgroundColor: item - 1 === currentIndex ? dotBgColor : '#fff',
            }"
            @click="dotClick(item - 1)"
          ></a>
        </div>
      </div>
      <div
        class="_dir-wrapper"
        v-if="hasDirector"
        @mouseenter="mouseEnter"
        @mouseleave="mouseLeave"
      >
        <div class="_director _prev">
          <a href="javascript:;" @click="dirClick('prev')">&lt;</a>
        </div>
        <div class="_director _next">
          <a href="javascript:;" @click="dirClick('next')">&gt;</a>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { reactive, toRefs, ref } from "@vue/reactivity";
import {
  getCurrentInstance,
  onMounted,
  onBeforeUnmount,
} from "@vue/runtime-core";
export default {
  name: "Slide",
  props: {
    autoplay: {
      type: Boolean,
      default: true,
    },
    duration: {
      type: Number,
      default: 3000,
    },
    hasDot: {
      type: Boolean,
      default: true,
    },
    hasDirector: {
      type: Boolean,
      default: true,
    },
    dotBgColor: {
      type: String,
      default: "#ff5000",
    },
  },
  setup(props, ctx) {
    const slideRef = ref(null);
    const instance = getCurrentInstance();
    const state = reactive({
      currentIndex: 0,
      itemLength: 0,
    });
    let t = null;
    const autoPlay = () => {
      if (props.autoplay) {
        t = setInterval(() => {
          setIndex("next");
        }, props.duration);
      }
    };
    const setIndex = (direction) => {
      switch (direction) {
        case "next":
          state.currentIndex += 1;
          if (state.currentIndex === state.itemLength) {
            state.currentIndex = 0;
          }
          break;
        case "prev":
          state.currentIndex -= 1;
          if (state.currentIndex === -1) {
            state.currentIndex = state.itemLength - 1;
          }
          break;
        default:
          break;
      }
    };
    const dotClick = (idx) => {
      state.currentIndex = idx;
    };
    const dirClick = (dir) => {
      setIndex(dir);
    };
    const mouseEnter = () => {
      clearInterval(t);
      t = null;
    };
    const mouseLeave = () => {
      autoPlay();
    };
    const bindTouchEvent = () => {
      const slide = slideRef.value;
      let startX = 0,
        endX = 0,
        tranX = 0;
      slide.addEventListener("touchstart", (event) => {
        //event.preventDefault();
        startX = event.changedTouches[0].pageX;
      });
      slide.addEventListener("touchend", (event) => {
        //event.preventDefault();
        endX = event.changedTouches[0].pageX;
        tranX = startX - endX;
        if (tranX > 50) {
          setIndex("next");
        } else if (tranX < -50) {
          setIndex("prev");
        }
      });
    };
    onMounted(() => {
      const arr = instance.slots.default();
      if (arr[0].children.length) {
        state.itemLength = arr[0].children.length;
      } else state.itemLength = arr.length;
      autoPlay();
      bindTouchEvent();
    });
    onBeforeUnmount(() => {
      clearInterval(t);
      t = null;
    });
    return {
      ...toRefs(state),
      dotClick,
      dirClick,
      mouseLeave,
      mouseEnter,
      slideRef,
    };
  },
};
</script>

<style>
._slide {
  width: 100%;
  height: 100%;
}
._slide .inner {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
}
._dot-wrapper {
  width: 50px;
  height: 13px;
  border-radius: 10px;
  position: absolute;
  bottom: 15px;
  text-align: center;
  font-size: 0;
  left: 50%;
  z-index: 70;
  margin-left: -39px;
  background-color: rgba(255, 255, 255, 0.3);
}
._dot-item {
  display: inline-block;
  margin: 3px;
}
._dot-item .dot-link {
  display: block;
  padding-top: 8px;
  width: 8px;
  height: 0;
  border-radius: 50%;
  background-color: #fff;
}
._director {
  position: absolute;
  top: 50%;
  z-index: 70;
  transform: translateY(-50%);
  border: 2px solid rgba(255, 255, 255, 0.5);
  border-radius: 4px;
  box-shadow: 0 0.25em 0.5em 0 rgb(0 0 0 / 10%);
  text-shadow: 0 0.25em 0.5em rgb(0 0 0 / 10%);
  opacity: 1;
  cursor: pointer;
  transition: opacity 150ms ease, border 300ms ease-in-out;
}
._director a {
  display: block;
  padding: 7px 11px;
  color: #fff;
  font-size: 14px;
  text-decoration: none;
}
._director._next {
  position: absolute;
  top: 50%;
  right: 2rem;
}
._director._prev {
  position: absolute;
  top: 50%;
  left: 1rem;
}
@media (max-width: 500px) {
  ._dir-wrapper {
    display: none;
  }
}
</style>